package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.mapper.UserInfoMapper;
import com.example.java_gobang.model.UserInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

//这个类是关于游戏房间的一个类
@Data
public class Room {
    //使用String来表示唯一的房间ID，通过UUID的算法来获取唯一的"ID"
    private String roomId;

    //转换JSON字符串
    private ObjectMapper objectMapper = new ObjectMapper();

    private UserInfo userInfo1;
    private UserInfo userInfo2;

    //需要手动注入
    private RoomManager roomManager;

    //需要手动注入
    private OnlineUserManager onlineUserManager;

    //需要手动注入
    private UserInfoMapper userInfoMapper;

    private static final int MAX_ROW = 15;


    private static final int MAX_COL = 15;


    //先落子的人
    private int whiteUserId;

    public Room() {
        //通过UUID创建唯一的"Id"
        this.roomId = UUID.randomUUID().toString();
        //进行手动注入对象(不是单例，是多例)
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userInfoMapper = JavaGobangApplication.context.getBean(UserInfoMapper.class);
    }


    //使用这个二维数组来表示棋盘
    //约定：
    // 1) 当这个位置没有落子的时候为0
    // 2) 当这个位置被玩家1落子后为1
    // 3) 当这个位置被玩家2落子后为2
    private int[][] board = new int[MAX_ROW][MAX_COL];

    //处理一次落子的逻辑
    public void putChess(String requestJson) throws IOException {
        // 1)记录当前落子位置信息
        //获取客户端的JSON请求
        GameRequest request = objectMapper.readValue(requestJson,GameRequest.class);
        GameResponse  response = new GameResponse();
        int row = request.getRow();
        int col = request.getCol();
        //判断棋盘，当前落子的位置是否有子
        if (board[row][col] != 0) {
            //当前位置已经落子
            System.out.println("当前位置"+ row +"行" + col + "列"+"已经落子");
            return;
        }
        //判断当前的userId来确定下棋的地方是1还2
        int chess = (request.getUserId() == userInfo1.getId()) ? 1 : 2;
        board[row][col] = chess;

        //绘制当前棋盘
        printBoard();


        // 2)判定胜负 (不能将胜负放在客户端，容易被对方进行篡改)
        int winner = checkWinner(row,col, chess);

        // 3)将响应返回给客户端
        response.setCol(col);
        response.setRow(row);
        response.setWinner(winner);
        response.setMessage("putChess");
        response.setUserId(request.getUserId());

        //通过onlineUserManager获取用户的WebSocketSession来讲响应数据传回客户端
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(userInfo1.getId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(userInfo2.getId());

        if (session1 == null) {
            //此时代表玩家1掉线，玩家2获胜
            System.out.println("玩家1掉线");
            response.setWinner(userInfo2.getId());
        }

        if (session2 == null) {
            //此时代表玩家2掉线，玩家1获胜
            System.out.println("玩家2掉线");
            response.setWinner(userInfo1.getId());
        }

        if (session1 != null) {
            session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

        if (session2 != null) {
            session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

        //胜负分出后，房间失去存在的意义，需要销毁房间
        if (response.getWinner() != 0) {
            System.out.println("游戏结束，房间: "+roomId + "即将消失," + "获胜者: " + response.getWinner());
            //对玩家的信息进行修改
            userInfoMapper.updateWinnerById(response.getWinner());
            userInfoMapper.updateLoserById(response.getWinner() == userInfo1.getId() ? userInfo2.getId() : userInfo1.getId());

            roomManager.remove(roomId,userInfo1.getId(),userInfo2.getId());
        }

    }

    private void printBoard() {
        System.out.println("打印棋盘信息" + roomId);
        System.out.println("-------------------------------------------------------------------");
        for (int row = 0; row < MAX_ROW; row++) {
            for (int col = 0; col < MAX_COL; col++) {
                System.out.print(board[row][col] + " ");
            }
            System.out.println();
        }
        System.out.println("-------------------------------------------------------------------");
    }

    private int checkWinner(int row, int col, int chess) {
        //c代表此时落子位置从最右边的位置移到最左边的位置
        //意思是，要有五个相同颜色的棋子获胜的话，此时落子的位置，左边应该有4个与之相同颜色的棋子
        //并且，此时c会不断增大，那么落子位置的棋子从最右边不断地往左边移动
        //当c一次循环完毕后，进行了c++操作后，此时要获胜的五颗棋子的形状
        //应该是当前落子位置左边3颗棋子，右边1颗棋子的样子才获胜，其他以此类推
        //此时是以列来看获胜的情况
        for (int c = col - 4; c <= col; c++) {
            try {
                if (board[row][c] == chess
                && board[row][c + 1] == chess
                && board[row][c + 2] == chess
                && board[row][c + 3] == chess
                && board[row][c + 4] == chess) {
                    return chess == 1 ? userInfo1.getId() : userInfo2.getId();
                }
            }catch(ArrayIndexOutOfBoundsException e) {
                //处理数组越界异常
                continue;
            }
        }

        //此时看行获胜的情况
        for (int r = row - 4; r <= row; r++) {
            try {
                if (board[r][col] == chess
                        && board[r + 1][col] == chess
                        && board[r + 2][col] == chess
                        && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? userInfo1.getId() : userInfo2.getId();
                }
            }catch(ArrayIndexOutOfBoundsException e) {
                //处理数组越界异常
                continue;
            }
        }

        //判断左对角线获胜的情况
        for (int c = col - 4,r = row - 4; c <= col && r <= row; c++,r++) {
            try {
                if (board[r][c] == chess
                && board[r + 1][c + 1] == chess
                && board[r + 2][c + 2] == chess
                && board[r + 3][c + 3] == chess
                && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? userInfo1.getId() : userInfo2.getId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //判断右对角线
        for (int c = col + 4,r = row - 4; c >= col && r <= row; c--,r++) {
            try {
                if (board[r][c] == chess
                && board[r + 1][c - 1] == chess
                && board[r + 2][c - 2] == chess
                && board[r + 3][c - 3] == chess
                && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? userInfo1.getId() : userInfo2.getId();
                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        //胜负未分,直接返回 0
        return 0;
    }
}
